Graviton3 を利用してコスパに優れる Redmine 環境を構築してみた
こんにちは。テクニカルサポートチームのShiinaです。
はじめに
プロジェクトのタスク管理や課題管理のツールとして Redmine を利用する場合があります。
新規プロジェクト立ち上げの機会にツールを調達したいといったこともよくありますよね。
今回はコスパが良い Arm ベースの AWS Graviton3 の EC2 インスタンスに Redmine を一から構築してみました。
構築手順とハマったポイントなどをご紹介します。
前提
プロジェクトメンバーやお客様とのタスク管理に利用することを想定しています。
コスト重視の構成を取るため、冗長化は行いませんので、必要に応じて検討ください。
Redmine では添付ファイルによりストーレージが逼迫しやすいため、将来の拡張性を考慮したストレージ設計を行います。
また、ドメイン取得済みであることを前提としています。
-
インフラ
単一の EC2 インスタンスに Web サーバと DB を構築します。
ALB と RDS は使用しません。 -
ストレージ
ルートボリュームとデータボリュームを分離します。 -
実行ユーザ
Redmine アプリケーション実行用ユーザ名として「redmine」を使用します。
EC2 インスタンス
検証したインスタンス情報は次の通りです。
- OS: Ubuntu Server 24.04 LTS 64 bit Arm
- AMI: ami-007bc34ad4cc33773
- インスタンスタイプ: m7g.medium
- EBS ボリューム: ルート用途 20 GB、データ用途 40 GB
利用バージョン
利用したコンポーネントのバージョンは次の通りです。
- Redmine: 5.1.3
- Ruby: 3.1.2
- MariaDB: 10.11.8
- Bundler: 2.5.20
構築の流れ
はじめにデータ用途の EBS ボリュームのフォーマットおよびマウントの永続化を行います。
次に必要なパッケージをインストールした後、MariaDB のデータディレクトリの引越しを行います。
その後、Ruby、Bundler をインストールして Redmine のインストールおよびセットアップを進めて行きます。
最後に Let's Encrypt 証明書を発行して HTTPS 通信の設定を行います。
構築手順
EC2 インスタンス作成
インスタンスタイプ、AMI、VPC、サブネット、セキュリティグループなどを指定して EC2 インスタンスを作成および EBS ボリュームをアタッチします。
ElasticIP 取得の上、EC2 インスタンスに割り当てておきます。
セキュリティグループの設定では HTTP、HTTPS のインバウンド通信を許可しておきます。
EBS ボリュームのフォーマットとマウント
ディスクデバイス確認の上、データ用の EBS ボリュームを /data にマウントとします。
lsblk -f
sudo file -s /dev/nvme0n1
sudo mkfs -t xfs /dev/nvme0n1
sudo mkdir /data
sudo mount /dev/nvme0n1 /data
EBS ボリュームのマウントを永続化するように UUID を確認の上、fstab を修正します。
sudo blkid
sudo vi /etc/fstab
UUID=xxxxx-xxxx-xxxx-xxxx-xxxxx /data xfs defaults,nofail 0 2
sudo umount /data
sudo mount -a
必要パッケージインストール
パッケージ情報の更新します。
sudo apt update
sudo apt upgrade
必要なパッケージ類をインストールします。
sudo apt install ruby ruby-dev build-essential libmariadb-dev imagemagick libmagickwand-dev git curl libssl-dev libreadline-dev zlib1g-dev autoconf bison libyaml-dev libncurses5-dev libffi-dev libgdbm-dev apache2 libapache2-mod-passenger mariadb-server mariadb-client
Ruby インストール
rbenv と ruby-build を clone します。
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
Ruby をインストールします。
rbenv install 3.1.2
rbenv global 3.1.2
※5分〜10分程度時間を要しますのでしばらくお待ちください。
Bundler インストール
sudo gem install bundler
MariaDB のデータディレクトリ移動
MariaDB のデータディレクトリを /data へ移動します。
sudo systemctl stop mariadb.service
sudo mkdir /data/mysql_data
sudo chmod 755 /data/mysql_data
sudo chown mysql:mysql /data/mysql_data
sudo cp -rfp /var/lib/mysql/* /data/mysql_data/
移動先のデータディレクトリを参照するように conf を修正します。
sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
datadir=/data/mysql_data
sudo systemctl start mariadb.service
Redmine 用データベースとユーザー作成
Redmine 用の MariaDB データベースとユーザーを作成します。
sudo mysql -u root -p
※Enter password とパスワードが求められますが、入力せずそのままエンターでログインできます。
CREATE DATABASE redmine CHARACTER SET utf8mb4;
CREATE USER 'redmine'@'localhost' IDENTIFIED BY 'YourPassword';
GRANT ALL PRIVILEGES ON redmine.* TO 'redmine'@'localhost';
FLUSH PRIVILEGES;
ついでに root のパスワードも変更しておきます。
USE mysql;
ALTER USER 'root'@'localhost' IDENTIFIED BY 'YourAdminPassword';
EXIT;
Redmine ダウンロード
Redmine をダウンロードして解凍します。
cd /data
sudo wget https://www.redmine.org/releases/redmine-5.1.3.tar.gz
sudo tar xzf redmine-5.1.3.tar.gz
sudo mv redmine-5.1.3 redmine
サンプルファイルをコピーしてデータベース接続用のコンフィグファイルを用意します。
cd /data/redmine/config
sudo cp database.yml.example database.yml
sudo vi database.yml
production:
adapter: mysql2
database: redmine
host: localhost
username: redmine
password: "YourPassword"
# Use "utf8" instead of "utfmb4" for MySQL prior to 5.7.7
encoding: utf8mb4
variables:
# Recommended `transaction_isolation` for MySQL to avoid concurrency issues is
# `READ-COMMITTED`.
# In case of MySQL lower than 8, the variable name is `tx_isolation`.
# See https://www.redmine.org/projects/redmine/wiki/MySQL_configuration
# transaction_isolation: "READ-COMMITTED"
tx_isolation: "READ-COMMITTED"
(中略)
Gem インストール
cd /data/redmine
sudo bundle install --without development test
セッション保存用秘密鍵生成
sudo bundle exec rake generate_secret_token
データベースのセットアップ
sudo RAILS_ENV=production bundle exec rake db:migrate
デフォルトデータ設定
sudo RAILS_ENV=production REDMINE_LANG=ja bundle exec rake redmine:load_default_data
redmine ユーザ設定
sudo useradd -r -s /usr/sbin/nologin redmine
sudo chown -R redmine:redmine /data/redmine
Passenger 設定
デフォルトユーザを「redmine」と指定します。
sudo vi /etc/apache2/mods-available/passenger.conf
<IfModule mod_passenger.c>
PassengerRoot /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini
PassengerDefaultRuby /usr/bin/ruby
PassengerDefaultUser redmine
</IfModule>
Apache 設定
sudo vi /etc/apache2/sites-available/redmine.conf
<VirtualHost *:80>
ServerName redmine.example.com
DocumentRoot /data/redmine/public
<Directory /data/redmine/public>
AllowOverride all
Options -MultiViews
Require all granted
</Directory>
</VirtualHost>
有効化を行い、設定反映のためにサービスのリスタートを行います。
sudo a2enmod passenger
sudo a2ensite redmine
sudo systemctl restart apache2
ホストゾーンへのレコード登録
ドメイン名URLにアクセスできるよう、ドメインを管理しているパブリックホストゾーンにレコード名を登録します。
EC2 インスタンスに割り当てた ElasticIPアドレスを A レコードとして登録します。
動作確認(HTTP)
設定したドメイン名を指定して HTTP アクセスします。
http:/
問題なく設定ができていれば、ログイン画面が表示されるはずです。
初期管理者ユーザでログインします。
ID: admin
password: admin
HTTPS 通信設定
証明書設定のため一度 apache を停止します。
sudo systemctl stop apache2
certbot をインストールして証明書と秘密鍵を発行します。
sudo apt install certbot
sudo certbot certonly --standalone -d redmine.example.com
メールアドレス入力後、規約に同意を行うための Yes を入力します。
成功するとドメイン名を含む下記のようなディレクトリに証明書と秘密鍵が生成されます。
- /etc/letsencrypt/live/redmine.example.com/fullchain.pem
- /etc/letsencrypt/live/redmine.example.com/privkey.pem
証明書と秘密鍵を指定します。
また、HTTP アクセスを HTTPS アクセスにリダイレクトします。
sudo vi /etc/apache2/sites-available/redmine.conf
<VirtualHost *:443>
ServerName redmine.example.com
DocumentRoot /data/redmine/public
<Directory /data/redmine/public>
AllowOverride all
Options -MultiViews
Require all granted
</Directory>
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/redmine.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/redmine.example.com/privkey.pem
</VirtualHost>
<VirtualHost *:80>
ServerName redmine.example.com
Redirect permanent / https://redmine.example.com/
</VirtualHost>
有効化後、apache を起動します。
sudo a2enmod ssl
sudo systemctl start apache2
動作確認(HTTPS)
設定したドメイン名のURLを指定して HTTPS アクセスします。
https:/
HTTPS でアクセスできることを確認します。
ブラウザから利用している証明書も確認できます。
注意事項
Let's Encrypt 証明書の有効期限は 90 日のため、2ヶ月程度ごとに証明書の更新作業が必要です。
ハマったポイント
transaction_isolation エラー
- 事象
データベースセットアップ時に以下のエラーが発生。
sudo RAILS_ENV=production bundle exec rake db:migrate
Mysql2::Error: Unknown system variable 'transaction_isolation' (Mysql2::Error)
-
原因
database.yml ではデフォルトで transaction_isolation パラメータを使用しますが、
利用している RDBMS バージョンによっては tx_isolation パラメータを利用する必要があります。 -
対処
利用した MariaDB バージョン(10.11.8)では、tx_isolation を利用するようにパラメータを修正して実行したところうまく行きました。
Redmine の設定画面にアクセスすると Internal error が発生
- 事象
プロジェクトやチケット起票など通常の操作は問題ないのですが、なぜか設定画面にアクセスすると Internal error が発生。
- 原因
apache のエラーログにはパーミッション不足を示すエラーログが記録されていました。
Permission denied @ dir_s_mkdir - /opt/redmine/tmp/cache/D3B)
Ruby アプリケーションの実行ユーザが nobody になっていたのが原因でした。
ps -ef | grep redmine
nobody 1261 678 1 07:50 ? 00:00:03 Passenger AppPreloader: /data/redmine
nobody 1302 1261 0 07:50 ? 00:00:00 Passenger RubyApp: /data/redmine (production)
- 対処
passenger.conf にて PassengerDefaultUser パラメータで実行ユーザ名(redmine)を指定したところ、解消。
<IfModule mod_passenger.c>
PassengerRoot /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini
PassengerDefaultRuby /usr/bin/ruby
PassengerDefaultUser redmine
</IfModule>
ps -ef | grep redmine
redmine 1261 678 1 07:50 ? 00:00:03 Passenger AppPreloader: /data/redmine
redmine 1302 1261 0 07:50 ? 00:00:00 Passenger RubyApp: /data/redmine (production)
証明書発行に失敗する
- 事象
証明書発行時に以下のエラーが発生。
sudo certbot certonly --standalone -d redmine.example.com
Certbot failed to authenticate some domains (authenticator: standalone). The Certificate Authority reported these problems:
Domain: redmine.example.com
Type: connection
Detail: xxx.xxx.xxx.xxx: Fetching http://redmine.example.com/.well-known/acme-challenge/9mWilMxK1RQINk8BfocHy5M8JkUWyPfrB15BfHO22ws: Timeout duringconnect (likely firewall problem)
Hint: The Certificate Authority failed to download the challenge files from the temporary standalone webserver started by Certbot on port 80. Ensure that the listed domains point to this machine and that it can accept inbound connections from the internet.
-
原因
Let's Encrypt で証明書を発行する際に、特定ファイルに対して HTTP アクセスを行い、ドメイン所有者の確認が行われます。
インバウンド通信を特定 IP アドレスからのみ許可するような設定をセキュリティグループで行なっていたことが原因でした。 -
対処
セキュリティグループで HTTP アクセスのインバウンド許可を実施したところ、無事に証明書が発行できました。
VirtualHost 設定後に apache サービス起動失敗
- 事象
VirtualHost で SSLEngine 有効化と証明書の秘密鍵のパスを指定した後、 apache サービスを起動を実施したところ、起動に失敗。
systemctl start apache2
Job for apache2.service failed because the control process exited with error code.
See "systemctl status apache2.service" and "journalctl -xeu apache2.service" for details.
systemctl status apache2.service
× apache2.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/apache2.service; enabled; preset: enabled)
Active: failed (Result: exit-code) since Fri 2024-09-27 01:21:29 UTC; 21s ago
Duration: 37min 50.177s
Docs: https://httpd.apache.org/docs/2.4/
Process: 2763 ExecStart=/usr/sbin/apachectl start (code=exited, status=1/FAILURE)
CPU: 11ms
Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: Starting apache2.service - The Apache HTTP Server...
Sep 27 01:21:29 ip-10-0-0-233 apachectl[2765]: AH00526: Syntax error on line 9 of /etc/apache2/sites-enabled/redmine.conf:
Sep 27 01:21:29 ip-10-0-0-233 apachectl[2765]: Invalid command 'SSLEngine', perhaps misspelled or defined by a module not included in the server configuration
Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: apache2.service: Control process exited, code=exited, status=1/FAILURE
Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: apache2.service: Failed with result 'exit-code'.
Sep 27 01:21:29 ip-10-0-0-233 systemd[1]: Failed to start apache2.service - The Apache HTTP Server.
-
原因
SSL モジュールが有効化されいなかったことが原因でした。
SSLEngine を利用する場合はモジュールの有効化が必要です。 -
対象
a2enmod コマンドで ssl を有効化したところ、起動できるようになりました。
sudo a2enmod ssl
プラグイン動作確認
プラグインの動作も確認してみました。
試しにダークモードに変更するプラグインを導入してみましたが、問題なく動作しました。
cd /data/redmine/plugins
sudo -u redmine git clone https://github.com/fraoustin/redmine_dark
sudo systemctl restart apache2
まとめ
特別な考慮や手順など不要で Graviton3 の EC2 インスタンスでも Redmine を導入することができました。
構築を検討されてる方は Graviton3 を利用してコスパよく利用してみてはいかがでしょうか。
Let's Encrypt の証明書は有効期限が短いため、管理面がすこし煩わしいです。
コストは増えますが、ALB を利用する構成とすれば、ACM で発行した証明書を利用できるため、証明書の管理自体をなくこともできます。
本記事が誰かのお役に立てれば幸いです。
参考